﻿using System;
using System.Xml;
using System.Collections.Generic;
using System.Text;
using DirectUI.Common;
using System.Net;
using System.IO;
namespace DirectUI.Mobile.UI
{
    // Summary:
    //     Enables declarative access to XML data for data binding.
    public class XmlDataProvider : DataSourceProvider
    {
        private Dictionary<string, object> cache;
        // Summary:
        //     Initializes a new instance of the System.Windows.Data.XmlDataProvider class.
        public XmlDataProvider()
        {
            EnableCache = false;
            cache = new Dictionary<string, object>();
        }
        public void ClearCache()
        {
            if (cache != null)
            {
                cache.Clear();
            }
        }
        // Summary:
        //     This type or member supports the WPF infrastructure and is not intended to
        //     be used directly from your code.
        protected virtual Uri BaseUri { get; set; }
        //
        // Summary:
        //     Gets or sets the System.Xml.XmlDocument to use as the binding source.
        //
        // Returns:
        //     The System.Xml.XmlDocument to use as the binding source. The default value
        //     is null.
        private XmlDocument document;
        public XmlDocument Document
        {
            get
            {
                return document;
            }
            set
            {
                if (document != value)
                {
                    document = value;
                    BeginQuery();
                }
            }
        }
        //
        // Summary:
        //     Gets or sets a value that indicates whether node collection creation will
        //     be performed in a worker thread or in the active context.
        //
        // Returns:
        //     true to perform node collection creation in a worker thread; otherwise, false.
        //     The default value is true.
    
        public bool IsAsynchronous { get; set; }
        //
        // Summary:
        //     Gets or sets the System.Uri of the XML data file to use as the binding source.
        //
        // Returns:
        //     The System.Uri of the XML data file to use as the binding source. The default
        //     value is null.
        private Uri source;
        public Uri Source
        {
            get
            {
                return source;
            }
            set
            {
              
                if (source== value)
                {
                    return;
                }
                source = value;
                document = null;
                _data = null;
         
             //   OnDataChanged(null);
                if (AutoLoad)
                {
                    BeginQuery();
                }
                else
                {
                    State = DataSourceState.Waiting;
                }
            }
        }

        public override void Refresh()
        {
            if (this.State == DataSourceState.Loading)
            {
                return;
            }
            ClearCache();
            document = null;
            _data = null;
          //  State = DataSourceState.Waiting;
         //   OnDataChanged(null);
            base.Refresh();
        }
        //
        // Summary:
        //     Gets or sets the XPath query used to generate the data collection.
        //
        // Returns:
        //     The XPath query used to generate the data collection. The default is an empty
        //     string.

        public string XPath { get; set; }

        // Summary:
        //     Prepares the loading of either the inline XML or the external XML file to
        //     produce a collection of XML nodes.
        protected override void BeginQuery()
        {
            State = DataSourceState.Loading;
            if(cache.ContainsKey(source.ToString())){
                _data = cache[source.ToString()];
                State = DataSourceState.Ready;
#if DEBUG
                Log.Instance.Debug("XmlDocument BeginQuery:Find Data In The Cache,Url: " + source.ToString());
#endif
                return;
            }
            if (Document != null)
            {
                #if DEBUG
                Log.Instance.Debug("XmlDocument BeginQuery:Document Object is not Null: " + source.ToString());
#endif
                if (string.IsNullOrEmpty(XPath))
                {
                    _data = Document;
                }
                else
                {
                    _data = Document.SelectSingleNode(XPath);
                }
                if (EnableCache)
                {
                    cache.Add(source.ToString(), _data);
                }
            }
            else
            {
                if (Source != null)
                {
#if DEBUG
                    Log.Instance.Debug("XmlDocument BeginQuery:Access Server,Url : " + source.ToString());
#endif
                    sendRequest(Source, "GET", null);
                }
                else
                {
                    LastError = "未指定数据源";
                    State = DataSourceState.Error;
                }
            }
        }

        private void sendRequest(Uri url, string method, string postdata)
        {
            WebRequest rqst = HttpWebRequest.Create(url);
      
            // ((HttpWebRequest)rqst).AllowWriteStreamBuffering = true;

            rqst.Method = method;
            rqst.Timeout =10000;
            if (!String.IsNullOrEmpty(postdata)&&method=="POST")
            {
                rqst.ContentType = "application/x-www-form-urlencoded";
                byte[] byteData = UTF8Encoding.UTF8.GetBytes(postdata);
                rqst.ContentLength = byteData.Length;
                using (Stream postStream = rqst.GetRequestStream())
                { postStream.Write(byteData, 0, byteData.Length); postStream.Close(); }
            }
            ((HttpWebRequest)rqst).KeepAlive = false;
            rqst.BeginGetResponse(DataLoadedCB, rqst);
        }
        private void DataLoadedCB(IAsyncResult result)
        {
            WebRequest rqst = null;
            WebResponse rsps = null;
            StreamReader sr = null;
            try
            {
                rqst = ((WebRequest)(result.AsyncState));
                rsps = rqst.EndGetResponse(result);    /* ETC...*/
                sr = new StreamReader(rsps.GetResponseStream());
             
                string xml = sr.ReadToEnd();
              
                document = new XmlDocument();
                document.LoadXml(xml);
                if (string.IsNullOrEmpty(XPath))
                {
                    _data = document;
                }
                else
                {
                    _data = document.SelectSingleNode(XPath);
                }
                if (EnableCache)
                {
                    cache.Add(source.ToString(), _data);
                }
                this.State = DataSourceState.Ready;
                
            }
            catch (System.Exception ex)
            {
                this.LastError = ex.ToString();
                this.State = DataSourceState.Error;
        
              

            }
            finally
            {
                if (rsps != null)
                {
                    rsps.Close();
                }
            }

        }
        public bool EnableCache { get; set; }
    }
}
